package com.soyotec.algorithm.solution;

import com.soyotec.algorithm.problem.Problem;
import com.soyotec.algorithm.solution.value.SolutionValue;
import com.soyotec.algorithm.value.Limit;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public abstract class ValueWrapSolution<P extends Problem> implements Solution<SolutionValue,
        SolutionValue,
        SolutionValue> {
    private List<SolutionValue> objectives;
    private List<SolutionValue> weightObjectives;//权重化目标(有多少个目标，集合里就有多少个元素)
    private List<SolutionValue> constraints;//这个是距离
    private transient List<SolutionValue> constraintRealValue; //这个是真实值
    private List<SolutionValue> variables;
    private transient List<SolutionValue> realTypeVariables;//这个是设计变量的真实类型
    private boolean isFeasible = false;//本次方案是否可行
    private transient boolean execFlag = false;//子流程执行状态 true成功；false失败
    private String algorithmName;//执行的算法名称
    private Integer arrayDimension;//数组变量的维度
    private transient double objective;//目标权重和
    private transient double penalty; //罚值
    private transient double objectiveAndPenalty;//目标权重和+penalty
    private List<Double> objMinimization; //转换后的目标值（最大最小定值）
    protected Map<Object, Object> attributes;
    protected transient P problem;
    protected ValueWrapSolution(P problem ) {
        this.problem = problem;
        init();
    }

    protected ValueWrapSolution(ValueWrapSolution valueWrapSolution) {
        this.problem = (P) valueWrapSolution.getProblem();
        init();
    }

    private void init(){
        this.algorithmName = problem.getAlgorithmName();
        this.objMinimization = new ArrayList<>();
        this.arrayDimension = problem.getArrayDimension();
        this.attributes = new HashMap();
        this.variables = new ArrayList(problem.getNumberOfVariables());
        this.realTypeVariables = new ArrayList<>(problem.getNumberOfVariables());
        this.constraints =new ArrayList<>(problem.getNumberOfConstraints());
        this.constraintRealValue = new ArrayList<>(problem.getNumberOfConstraints());
        this.objectives =new ArrayList<>(problem.getNumberOfObjectives());
        this.weightObjectives = new ArrayList<>(problem.getNumberOfWeightObjectives());
        for(int i = 0; i < problem.getNumberOfVariables(); ++i) {
            this.variables.add(i, null);
            this.realTypeVariables.add(i,null);
        }
        for(int i = 0; i < problem.getNumberOfConstraints(); ++i) {
            this.constraints.add(i, null);
        }
        for(int i = 0; i < problem.getNumberOfConstraints(); ++i) {
            this.constraintRealValue.add(i, null);
        }
        for(int i = 0; i < problem.getNumberOfObjectives(); ++i) {
            this.objectives.add(i, null);
        }
        for(int i = 0; i < problem.getNumberOfWeightObjectives(); ++i) {
            this.weightObjectives.add(i, null);
        }
    }

    @Override
    public void setObjective(int var1, SolutionValue var2) {
        objectives.set(var1,var2);
    }

    @Override
    public void setConstraint(int var1, SolutionValue var2) {
        constraints.set(var1,var2);
    }

    @Override
    public SolutionValue getObjective(int var1) {
        return objectives.get(var1);
    }

    @Override
    public SolutionValue getConstraint(int var1) {
        return constraints.get(var1);
    }

    @Override
    public SolutionValue[] getObjectives() {
        SolutionValue[] warppers=new SolutionValue[objectives.size()];
        return  objectives.toArray(warppers);
    }

    public SolutionValue getWeightObjective(int var1) {
        return weightObjectives.get(var1);
    }

    public SolutionValue[] getWeightObjectives() {
        SolutionValue[] warppers=new SolutionValue[weightObjectives.size()];
        return  weightObjectives.toArray(warppers);
    }

    @Override
    public SolutionValue[] getConstraints() {
        SolutionValue[] warppers = new SolutionValue[constraints.size()];
        return  constraints.toArray(warppers);

    }

    @Override
    public SolutionValue[] getConstraintRealValue() {
        SolutionValue[] warppers = new SolutionValue[constraintRealValue.size()];
        return  constraintRealValue.toArray(warppers);

    }

    @Override
    public SolutionValue getConstraintRealValue(int index) {
        return constraintRealValue.get(index);
    }

    @Override
    public void setConstraintRealValue(int var1, SolutionValue var2) {
        constraintRealValue.set(var1,var2);
    }

    public void setWeightObjectivesValue(int var1, SolutionValue var2) {
        weightObjectives.set(var1,var2);
    }

    @Override
    public SolutionValue getVariableValue(int var1) {
        return variables.get(var1);
    }

    @Override
    public List<SolutionValue> getVariables() {
        return variables;
    }

    @Override
    public void setVariableValue(int var1, SolutionValue var2) {
        variables.set(var1,var2);
    }

    @Override
    public SolutionValue getRealTypeVariable(int var1){
        return realTypeVariables.get(var1);
    }

    @Override
    public List<SolutionValue> getRealTypeVariables(){
        return realTypeVariables;
    }

    @Override
    public void setRealTypeVariable(int var1, SolutionValue var2){
        realTypeVariables.set(var1,var2);
    }

    @Override
    public String getVariableValueString(int var1) {
        return variables.get(var1).getValue().getStringValue();
    }

    @Override
    public int getNumberOfVariables() {
        return variables.size();
    }

    @Override
    public int getNumberOfObjectives() {
        return objectives.size();
    }

    @Override
    public int getNumberOfConstraints() {
        return constraints.size();
    }

    public int getNumberOfWeightObjectives() {
        return weightObjectives.size();
    }

    @Override
    public void setAttribute(Object var1, Object var2) {
        attributes.put(var1,var2);
    }

    @Override
    public Object getAttribute(Object var1) {
        return attributes.get(var1);
    }

    @Override
    public Map<Object, Object> getAttributes() {
        return attributes;
    }

    @Override
    public Limit getVariableLimit(int var1) {
        return variables.get(var1).getLimit();
    }
    @Override
    public Limit getConstraintLimit(int var1) {
        return constraints.get(var1).getLimit();
    }
    public int hashCode() {
        int result = this.objectives.hashCode();
        result = 31 * result + this.variables.hashCode();
        result = 31 * result + this.attributes.hashCode();
        result = 31 * result + this.constraints.hashCode();
        return result;
    }

    @Override
    public boolean isFeasible() {
        return isFeasible;
    }

    public void setFeasible(boolean feasible) {
        isFeasible = feasible;
    }

    @Override
    public boolean isExecFlag() {
        return execFlag;
    }

    public void setExecFlag(boolean execFlag) {
        this.execFlag = execFlag;
    }

    @Override
    public double getPenalty() {
        return penalty;
    }

    public void setPenalty(double penalty) {
        this.penalty = penalty;
    }

    @Override
    public String getAlgorithmName() {
        return algorithmName;
    }

    @Override
    public Integer getArrayDimension() {
        return arrayDimension;
    }

    @Override
    public double getObjectiveAndPenalty() {
        return objectiveAndPenalty;
    }

    public void setObjectiveAndPenalty(double objectiveAndPenalty) {
        this.objectiveAndPenalty = objectiveAndPenalty;
    }

    public P getProblem() {
        return problem;
    }

    @Override
    public double getObjective(){return objective;}

    public void setObjective(double objective) {
        this.objective = objective;
    }

    public List<Double> getObjMinimization() {
        return objMinimization;
    }
}
